import { Feature } from 'ol' // 引入容器绑定模块和视图模块

import { Vector as VectorSource } from 'ol/source'
import { Point, LineString } from 'ol/geom' // 引入XYZ地图格式
import { Circle as StyleCircle, Fill, Stroke, Style } from 'ol/style' // 引入XYZ地图格式
import VectorLayer from 'ol/layer/Vector'
import 'ol/ol.css' // ol提供的css样式（必须引入）
import { getVectorContext } from 'ol/render'

/** @typedef {Any} CyID 公共 ID 类型 */

/**
 * @typedef {Object} CyMapRealPathPoint 实时路径初始化数据
 * @property {String} name 点位名称
 * @property {Number} x x 轴坐标
 * @property {Number} y y 轴坐标
 */

/**
 * @typedef {Object} CyMapRealPathInitOption 实时路径初始化数据
 * @property {CyMapRealPathPoint[]} points 路径点位
 */

/**
 * 地图应用类
 * @class CyMapRealPath
 * @param {CyMapOption} option 地图配置项
 */
export default class CyMapRealPath {
    /** @type {Map} 实例化的 OpenLayers.Map 对象 */
    map = null
    // CyMap 的实例
    cymap = null
    // vectorLayer
    layer = null
    // 路径的 lineString
    route = null
    geometryMove = null
    featureMove = null
    lineColor = 'rgba(237, 212, 0, 0.8)'
    pointColor = {
        bgc: 'blue',
        shadow: 'orange'
    }
    moveColor = {
        bgc: 'black',
        shadow: 'white'
    }
    // 点位的 source
    pointSource = null
    // 运动远点的背景园型尺寸
    moveRadius = 0
    // 当前路径的进行距离 0~1 之间
    distance = 0
    // 上次运动的时间
    lastTime = 0
    // 运动速度
    speed = 0.1

    /**
     * 实例化
     * @param {CyMapOption} option 地图类的配置项
     */
    constructor(option = {}) {
        if (!option.map) {
            throw Error('[CyMapRealPath]<constructor> option.map 参数缺失')
        }

        this.map = option.map
        this.styles = {
            route: new Style({
                stroke: new Stroke({
                    width: 6,
                    color: this.lineColor
                })
            }),
            icon: new Style({
                image: new StyleCircle({
                    radius: 7,
                    fill: new Fill({ color: this.pointColor.bgc }),
                    stroke: new Stroke({
                        color: this.pointColor.shadow,
                        width: 2
                    })
                })
            }),
            featureMove: new Style({
                image: new StyleCircle({
                    radius: 7,
                    fill: new Fill({ color: this.moveColor.bgc }),
                    stroke: new Stroke({
                        color: this.moveColor.shadow,
                        width: 4
                    })
                })
            })
        }

        this.moveFeature = this.moveFeature.bind(this)
    }

    /**
     * 初始化 地图实例
     * @memberof CyMapRealPath
     * @param {CyMapRealPathInitOption} option 地图初始化的配置项
     * @param {Function} callback 回调函数
     */
    init(option = {}, callback) {
        // 预设点位
        if (option.points) {
            this.createLayer(option.points)
        }

        // 回调做个延迟，用于等待数据渲染完成
        setTimeout(() => {
            callback && callback(this.map)
        }, 200)
    }

    // 设置播放速度
    setSpeed(value) {
        this.speed = value
    }

    /**
     * 创建路径和运动点位的图层
     * @param {CyMapRealPathPoint[]} points 点位数据
     * @returns
     */
    createLayer(points = []) {
        if (!points.length) {
            console.error('[CyMapRealPath]<createLayer> 至少需要一个点位')
            return
        }

        this.destroy()

        this.route = new LineString(
            points.map((p) => {
                return [p.x, p.y]
            })
        )

        this.geometryMove = new Point(this.route.getFirstCoordinate())

        this.featureMove = new Feature({
            type: 'featureMove',
            geometry: this.geometryMove
        })

        this.pointSource = new VectorSource({
            features: [
                new Feature({
                    type: 'route',
                    geometry: this.route
                }),
                new Feature({
                    type: 'icon',
                    geometry: new Point(this.route.getFirstCoordinate())
                }),
                new Feature({
                    type: 'icon',
                    geometry: new Point(this.route.getLastCoordinate())
                }),
                this.featureMove
            ]
        })

        this.layer = new VectorLayer({
            source: this.pointSource,
            style: (feature) => {
                return this.styles[feature.get('type')] || null
            }
        })

        this.map.addLayer(this.layer)
        // this.bindMoveRadius()
    }

    // 运动远点的外发光动画，未完成
    bindMoveRadius() {
        let radius = 0
        this.layer.on('postrender', (evt) => {
            if (radius >= 20) radius = 0
            let opacity = (20 - radius) * (1 / 20) //不透明度
            let pointStyle = new Style({
                image: new StyleCircle({
                    radius: radius,
                    stroke: new Stroke({
                        color: 'rgba(255,0,0' + opacity + ')',
                        width: 3 - radius / 10 //设置宽度
                    })
                })
            })
            // 获取矢量要素上下文
            let vectorContext = getVectorContext(evt)
            this.featureMove.setStyle(pointStyle)
            vectorContext.drawGeometry(this.featureMove.getGeometry())
            radius = radius + 0.3 //调整闪烁速度
            //请求地图渲染（在下一个动画帧处）
            this.map.render()
        })
    }

    // 点位运动动画
    moveFeature(e) {
        let time = e.frameState.time
        this.distance =
            this.distance + (this.speed * (time - this.lastTime)) / 1000
        this.lastTime = time

        const currentCoordinate = this.route.getCoordinateAt(
            this.distance > 1 ? 1 : this.distance
        )

        this.geometryMove.setCoordinates(currentCoordinate)

        const vectorContext = getVectorContext(e)

        vectorContext.setStyle(this.styles.featureMove)
        vectorContext.drawGeometry(this.geometryMove)

        this.map.render()

        if (this.distance >= 1) {
            this.distance = 0
            this.stopMove()
        }
    }

    // 开始运动
    startMove(reset) {
        if (reset) {
            this.distance = 0
        }

        this.lastTime = Date.now()
        this.layer.on('postrender', this.moveFeature)
        this.featureMove.setGeometry(null) //必须用null，不能用{}
    }

    // 停止运动
    stopMove(reset) {
        if (reset) {
            this.distance = 0
        }

        this.featureMove.setGeometry(this.geometryMove)
        this.layer.un('postrender', this.moveFeature)
    }

    /**
     * 销毁实例
     */
    destroy() {
        if (this.layer) {
            this.map.removeLayer(this.layer)
            this.layer = null
        }

        if (this.pointSource) {
            this.pointSource.clear()
            this.pointSource = null
            this.geometryMove = null
            this.featureMove = null
        }
    }
}
